class Compiler {
  constructor (vm) {
    this.vm = vm
    this.el = vm.options.el
    // 初始化模板编译
    console.log(vm, '====')
    this.compile(this.el)
  }

  // 基础模板方法
  compile (el) {
    const childNodes = el.childNodes
    Array.from(childNodes).forEach(node => {
      // 检测节点类型
      if (isTextNodes(node)) {
        // 编译文本节点内容
        this.compileText(node)
      } else if (isElementNode(node)) {
        // 编译元素节点内容
        this.compileElement(node)
      }
      // 检测当前节点是否存在子节点
      if (node.childNodes && node.childNodes.length) {
        this.compile(node)
      }
    })
  }
  compileText (node) {
    const reg = /\{\{(.+?)\}\}/g
    // 去除内容中不必要的换行
    const value = node.textContent.replace(/\s/g, '')
    // 声明数据存储多段文本
    const tokens = []
    // 记录已经操作过的索引值
    let lastIndex = 0
    // 当前提取内容的初始所以
    let index
    let result 
    while (result = reg.exec(value)) {
      index = result.index
      if (index > lastIndex) {
        // 将中间的内容存储到tokens中
        tokens.push(value.slice(lastIndex, index))
      }
      // 处理差值表达式内容
      const key = result[1].trim()
      // 根据key获取对应属性值，存储到tokens
      tokens.push(this.vm[key])

      // 更新lastIndex
      lastIndex = index + result[0].length

      // 更新视图
      // 创建订阅者，订阅数据变化
      const pos = tokens.length - 1 
      new Watcher(this.vm, key, newValue => {
        // 数据变化，修改tokens的对应数据
        // console.log('数据变化')
        tokens[pos] = newValue
        node.textContent = tokens.join('')
      })
    }
    // 页面初始渲染
    node.textContent = tokens.join('')
  }
  
  compileElement (node) {
    // 获取属性节点
    console.log(node)
    Array.from(node.attributes).forEach( attr => {
      // 保存属性名称，检测属性功能
      let attrName = attr.name
      if (!isDirective(attrName)){
        return
      }
      // 获取指令的具体名称
      attrName = attrName.slice(2)
      // 获取指令的值，代表响应式数据的名称
      console.dir(attr)
      let key = attr.value
      // 封装update方法，用于进行不同指令的处理操作
      this.update(node, key, attrName)  
    })
  }

  // 用于指令分配的方法
  update (node, key, attrName){
    // 名称处理
    let updateFn = this[attrName + 'Updater']
    // 检测并调用
    updateFn && updateFn.call(this, node, key, this.vm[key])
  } 

  //  v-text处理
  textUpdater(node, key, value){
    // 给元素设置内容
    node.textContent = value
    // 订阅数据变换
    new Watcher(this.vm, key, newValue => {
      node.textContent = newValue
    })
  }

  //  v-model处理
  modelUpdater(node, key, value){
    // 给元素设置数据
    console.log(node, key, value)
    node.value = value
    // 订阅数据变换
    new Watcher(this.vm, key, newValue => {
      node.value = newValue
    })
    // 监听input事件，实现双向绑定
    node.addEventListener('input', () => {
      this.vm[key] = node.value
    })
  }
}
// 判断元素是否是元素节点
function isElementNode (node) {
  return node.nodeType === 1
}

// 判断元素是否是文本节点
function isTextNodes (node) {
  return node.nodeType === 3
}

// 判断属性名是否为指令
function isDirective ( attrName ) {
  return attrName.startsWith('v-')
}